home *** CD-ROM | disk | FTP | other *** search
/ Ian & Stuart's Australian Mac 1993 September / September 93.iso / Archives / Games / Strategy / Puzzle / GameMaster / GM Dev Kit / Rulebook Sources / File Transfer ƒ / File Transfer.p next >
Encoding:
Text File  |  1991-12-04  |  12.6 KB  |  608 lines  |  [TEXT/PJMM]

  1. unit FileTransfer;
  2.  
  3. { File Transfer © Peter Lewis, Oct 1991 }
  4. { This program and its source are Povertyware }
  5.  
  6. interface
  7.  
  8. { Combining the world's most boring game with the world's slowest ever file transfer }
  9. { (OK, so the file transfer we used to send a file IN thru a centronics printer port }
  10. { might have been a bit slower, but this one is almost as good :-) }
  11.  
  12.     uses
  13.         GameTypes, FixMath;
  14.  
  15.     procedure Main (var ger: gameEventRecord);
  16.  
  17. implementation
  18.  
  19.     const
  20.         PAvailable = fsCurPerm;
  21.         PIn = fsRdPerm;
  22.         POut = fsWrPerm;
  23.         PInOut = fsRdWrPerm;
  24.         PShared = fsRdWrShPerm;
  25.  
  26.     const
  27.         dialog_button = 1;
  28.         dialog_fillbar = 2;
  29.         my_dialog_item = 3;
  30.         max_msg_len = 240;
  31.         bad_refnum = 8000;
  32.  
  33. { Format}
  34. { name:string[63] (ie, 64 bytes) }
  35. { Type:OSType}
  36. { Creator:OSType}
  37. { Flags:integer}
  38. { DataLen:longInt}
  39. { RsrcLen:longInt}
  40. { Datafork (DataLen bytes)}
  41. { Rsrcfork (RsrcLen bytes)}
  42.  
  43.     type
  44.         header = packed record
  45.                 name: str63;
  46.                 typ: OSType;
  47.                 crt: OSType;
  48.                 flags: integer;
  49.                 datalen: longInt;
  50.                 rsrclen: longInt;
  51.             end;
  52.         connectionStateType = (cs_Local, cs_Remote);
  53.         globalsPeek = ptr;
  54.         block = packed array[1..max_msg_len] of byte;
  55.         fork = (F_None, F_GotHeader, F_Data, F_Rsrc, F_Both);
  56.         filespec = record
  57.                 head: header;
  58.                 vrn: integer;
  59.                 dirID: longInt;
  60.                 refnum: integer;
  61.                 remains: longInt;
  62.                 state: fork;
  63.             end;
  64.         gameRecord = record
  65.                 globals: globalsPeek;
  66.                 connectionstate: connectionStateType;
  67.                 send, receive: filespec;
  68.             end;
  69.         gamePeek = ^gameRecord;
  70.  
  71.     procedure Fail (s: str255);
  72.     begin
  73.         DebugStr(s);
  74.     end;
  75.  
  76.     procedure MyDebug (s: string; n: longint);
  77.         var
  78.             numstr: str255;
  79.     begin
  80.         NumToString(n, numstr);
  81.         DebugStr(concat(s, numstr));
  82.     end;
  83.  
  84.     procedure DrawGame (wp: windowPtr; item: integer);
  85.         var
  86.             ggame: gamePeek;
  87.             ghandle, h: handle;
  88.             k: integer;
  89.             r: rect;
  90.         procedure DrawProgress (fs: filespec; topbar: boolean; r: rect);
  91.             procedure FillBit (r: rect; v1, v2: integer; pat: pattern);
  92.             begin
  93.                 r.left := v1;
  94.                 r.right := v2;
  95.                 FillRect(r, pat);
  96.             end;
  97.             var
  98.                 black, white: pattern;
  99.                 i, mid: integer;
  100.                 count, size: longInt;
  101.         begin
  102.             for i := 0 to 7 do begin
  103.                 black[i] := $FF;
  104.                 white[i] := 0;
  105.             end;
  106.             with r do
  107.                 if topbar then
  108.                     bottom := (top + bottom) div 2
  109.                 else
  110.                     top := (top + bottom) div 2;
  111.             FrameRect(r);
  112.             InsetRect(r, 1, 1);
  113.             with fs.head do
  114.                 case fs.state of
  115.                     F_Data:  begin
  116.                         size := datalen + rsrclen;
  117.                         count := datalen - fs.remains;
  118.                     end;
  119.                     F_Rsrc:  begin
  120.                         size := datalen + rsrclen;
  121.                         count := size - fs.remains;
  122.                     end;
  123.                     otherwise begin
  124.                         count := 0;
  125.                         size := 1;
  126.                     end;
  127.                 end;
  128.             mid := FracMul(r.right - r.left, FracDiv(count, size));
  129.             if topbar then begin
  130.                 FillBit(r, r.left, r.left + mid, black);
  131.                 FillBit(r, r.left + mid, r.right, white);
  132.             end
  133.             else begin
  134.                 FillBit(r, r.left, r.right - mid, white);
  135.                 FillBit(r, r.right - mid, r.right, black);
  136.             end;
  137.         end;
  138.     begin
  139.         ghandle := handle(GetWRefCon(wp));
  140.         HLock(ghandle);
  141.         ggame := gamePeek(ghandle^);
  142.         GetDItem(wp, item, k, h, r);
  143.         DrawProgress(ggame^.send, true, r);
  144.         DrawProgress(ggame^.receive, false, r);
  145.         HUnlock(ghandle);
  146.     end;
  147.  
  148.     procedure Main (var ger: gameEventRecord);
  149.         var
  150.             gglobals: globalsPeek;
  151.             ggame: gamePeek;
  152.             gwindow: windowPtr;
  153.             ghandle: handle;
  154.  
  155.         procedure PackStr (var b: block; len: integer; ch: char; var s: str255);
  156.             var
  157.                 i: integer;
  158.         begin
  159.             s := ch;
  160. {$PUSH}
  161. {$R-}
  162.             s[0] := chr(len + 1);
  163. {$POP}
  164.             BlockMove(@b, @s[2], len);
  165.         end;
  166.  
  167.         procedure UnpackStr (var s: str255; var b: block; var len: integer);
  168.             var
  169.                 i: integer;
  170.         begin
  171.             len := length(s) - 1;
  172.             BlockMove(@s[2], @b, len);
  173.         end;
  174.  
  175.         procedure SetMyTurn;
  176.         begin
  177.             ger.myturn := true;
  178.         end;
  179.  
  180.         procedure NextPlayer;
  181.         begin
  182.             SetMyTurn;
  183.         end;
  184.  
  185.         procedure UpdateControls;
  186.         begin
  187.             DrawGame(gwindow, dialog_fillbar);
  188.         end;
  189.  
  190.         function MFSOpenDF (var rn: integer; wdrn: integer; dirID: longInt; name: str63; perm: integer): OSErr;
  191.             var
  192.                 pb: HParamBlockRec;
  193.         begin
  194.             with pb do begin
  195.                 ioNamePtr := @name;
  196.                 ioVRefNum := wdrn;
  197.                 ioPermssn := perm;
  198.                 ioMisc := nil;
  199.                 ioDirID := dirID;
  200.                 MFSOpenDF := PBHOpen(@pb, false);
  201.                 rn := ioRefNum;
  202.             end;
  203.         end;
  204.  
  205.         function MFSOpenRF (var rn: integer; wdrn: integer; dirID: longInt; name: str63; perm: integer): OSErr;
  206.             var
  207.                 pb: HParamBlockRec;
  208.         begin
  209.             with pb do begin
  210.                 ioNamePtr := @name;
  211.                 ioVRefNum := wdrn;
  212.                 ioPermssn := perm;
  213.                 ioMisc := nil;
  214.                 ioDirID := dirID;
  215.                 MFSOpenRF := PBHOpenRF(@pb, false);
  216.                 rn := ioRefNum;
  217.             end;
  218.         end;
  219.  
  220.         procedure CloseFork (var refnum: integer);
  221.             var
  222.                 oe: OSErr;
  223.         begin
  224.             if refnum <> bad_refnum then
  225.                 oe := FSClose(refnum);
  226.             refnum := bad_refnum;
  227.         end;
  228.  
  229.         procedure SetButtonState;
  230.             var
  231.                 k: integer;
  232.                 r: rect;
  233.                 h: controlHandle;
  234.         begin
  235.             GetDItem(gwindow, dialog_button, k, handle(h), r);
  236.             with ggame^ do begin
  237.                 if (connectionState = cs_remote) and (send.state = F_None) then
  238.                     HiliteControl(h, 0)
  239.                 else
  240.                     HiliteControl(h, 255);
  241.             end;
  242.         end;
  243.  
  244.         procedure StartNextFork (var fs: filespec; priv: integer);
  245.             var
  246.                 rn: integer;
  247.                 oe: OSErr;
  248.         begin
  249.             with fs do begin
  250.                 CloseFork(refnum);
  251.                 if state < F_Data then
  252.                     with head do begin
  253.                         if datalen > 0 then begin
  254.                             oe := MFSOpenDF(rn, vrn, dirID, name, priv);
  255.                             if oe = noErr then begin
  256.                                 state := F_Data;
  257.                                 refnum := rn;
  258.                                 remains := head.datalen;
  259.                                 exit(StartNextFork);
  260.                             end;
  261.                         end;
  262.                     end;
  263.                 if state < F_Rsrc then
  264.                     with head do
  265.                         if rsrclen > 0 then begin
  266.                             oe := MFSOpenRF(rn, vrn, dirID, name, priv);
  267.                             if oe = noErr then begin
  268.                                 state := F_Rsrc;
  269.                                 refnum := rn;
  270.                                 remains := rsrclen;
  271.                                 exit(StartNextFork);
  272.                             end;
  273.                         end;
  274.                 state := F_none;
  275.                 SetButtonState;
  276.             end;
  277.         end;
  278.  
  279.         procedure DoMove (s: str255);
  280.             var
  281.                 b: block;
  282.                 len: integer;
  283.                 count: longInt;
  284.                 oe: OSErr;
  285.         begin
  286.             if length(s) > 0 then
  287.                 case s[1] of
  288.                     'H': 
  289.                         with ggame^.receive do
  290.                             if state = F_None then begin
  291.                                 UnpackStr(s, b, len);
  292.                                 if len <> SizeOf(header) then begin
  293.                                     ger.event := ge_SendMessage;
  294.                                     ger.message := 'N';
  295.                                 end
  296.                                 else begin
  297.                                     BlockMove(@b, @head, SizeOf(header));
  298.                                     state := F_GotHeader;
  299.                                     ger.event := ge_Ask;
  300.                                     ger.message := concat('Receive File “', head.name, '”');
  301.                                     ger.but1 := 'No';
  302.                                     ger.but2 := 'Yes';
  303.                                 end;
  304.                             end;
  305.                     'M': 
  306.                         with ggame^.receive do
  307.                             if state in [F_Data, F_Rsrc] then begin
  308.                                 UnpackStr(s, b, len);
  309.                                 count := len;
  310.                                 oe := FSWrite(refnum, count, @b);
  311.                                 remains := remains - len;
  312.                                 if remains <= 0 then
  313.                                     StartNextFork(ggame^.receive, POut);
  314.                                 UpdateControls;
  315.                             end;
  316.                     'Y': 
  317.                         with ggame^.send do begin
  318.                             refnum := bad_refnum;
  319.                             StartNextFork(ggame^.send, PIn);
  320.                             SetButtonState;
  321.                         end;
  322.                     'N':  begin
  323.                         ggame^.send.state := F_None;
  324.                         SetButtonState;
  325.                     end;
  326.                 end;
  327.         end;
  328.  
  329.         procedure DoIdle;
  330.             var
  331.                 count: longInt;
  332.                 b: block;
  333.                 oe: OSErr;
  334.         begin
  335.             with ggame^.send do
  336.                 if state > F_GotHeader then begin
  337.                     count := remains;
  338.                     if count > max_msg_len then
  339.                         count := max_msg_len;
  340.                     oe := FSRead(refnum, count, @b);
  341.                     PackStr(b, count, 'M', ger.message);
  342.                     ger.event := ge_SendMessage;
  343.                     remains := remains - count;
  344.                     if count <= 0 then
  345.                         StartNextFork(ggame^.send, PIn);
  346.                     UpdateControls;
  347.                 end;
  348.         end;
  349.  
  350.         function MFSCreate (wdrn: integer; dirID: longInt; name: str255; c, t: OSType; flags: integer): OSErr;
  351.             var
  352.                 ooe, oe: integer;
  353.                 fi: Finfo;
  354.         begin
  355.             oe := HCreate(wdrn, dirID, name, c, t);
  356.             if oe = dupFNErr then begin
  357.                 ooe := HGetFInfo(wdrn, dirID, name, fi);
  358.                 oe := HDelete(wdrn, dirID, name);
  359.                 oe := HCreate(wdrn, dirID, name, c, t);
  360.                 if (oe = noErr) and (ooe = noErr) then begin
  361.                     fi.fdType := t;
  362.                     fi.fdCreator := c;
  363.                     fi.fdFlags := flags;
  364.                     ooe := HSetFInfo(wdrn, dirID, name, fi);
  365.                 end;
  366.             end;
  367.             MFSCreate := oe;
  368.         end;
  369.  
  370.         procedure DoAnswer (ans: integer);
  371.             var
  372.                 reply: SFReply;
  373.                 pt: point;
  374.                 oe: OSErr;
  375.         begin
  376.             ger.event := ge_SendMessage;
  377.             if ans = 2 then
  378.                 with ggame^.receive do begin
  379.                     pt := point($00280028);
  380.                     SFPutFile(pt, 'Receive file:', head.name, nil, reply);
  381.                     if reply.good then begin
  382.                         ger.message := 'Y';
  383.                         head.name := reply.fname;
  384.                         dirID := 0;
  385.                         vrn := reply.vRefNum;
  386.                         oe := MFSCreate(vrn, dirID, head.name, head.crt, head.typ, head.flags);
  387.                         refnum := bad_refnum;
  388.                         if oe <> noErr then
  389.                             ans := -1
  390.                         else
  391.                             StartNextFork(ggame^.receive, POut);
  392.                     end
  393.                     else
  394.                         ans := -1;
  395.                 end;
  396.             if ans <> 2 then begin
  397.                 ger.message := 'N';
  398.                 ggame^.receive.state := F_None;
  399.             end;
  400.         end;
  401.  
  402.         procedure DoSend;
  403.             var
  404.                 reply: SFReply;
  405.                 pt: point;
  406.                 typeList: SFTypelist;
  407.                 s: str255;
  408.                 fi: FInfo;
  409.                 pb: ParamBlockRec;
  410.                 b: block;
  411.                 oe: OSErr;
  412.         begin
  413.             pt := point($00280028);
  414.             SFGetFile(pt, 'Send file:', nil, -1, typeList, nil, reply);
  415.             if reply.good then begin
  416.                 with ggame^.send, head do begin
  417.                     name := reply.fname;
  418.                     vrn := reply.vrefnum;
  419.                     dirID := 0;
  420.                     with pb do begin
  421.                         ioNamePtr := @name;
  422.                         ioVRefNum := vrn;
  423.                         ioVersNum := 0;
  424.                         ioFDirIndex := 0;
  425.                         oe := PBGetFInfo(@pb, false);
  426.                         typ := ioFlFndrInfo.fdType;
  427.                         crt := ioFlFndrInfo.fdCreator;
  428.                         flags := ioFlFndrInfo.fdFlags;
  429.                         datalen := ioFlLgLen;
  430.                         rsrclen := ioFlRLgLen;
  431.                     end;
  432.                     BlockMove(@head, @b, SizeOf(header));
  433.                     PackStr(b, SizeOf(header), 'H', ger.message);
  434.                     ger.event := ge_SendMessage;
  435.                     state := F_GotHeader;
  436.                     SetButtonState;
  437.                 end;
  438.             end;
  439.         end;
  440.  
  441.         procedure InitRuleBook;
  442.             var
  443.                 i: integer;
  444.                 rct: rect;
  445.                 hdl: handle;
  446.                 mid: integer;
  447.         begin
  448.             ger.globals := nil;
  449.             gglobals := globalsPeek(ger.globals);
  450.             with rct do begin
  451.                 hdl := GetResource('DITL', 128);
  452.                 if hdl = nil then begin
  453.                     Fail('GetResource DITL failed');
  454.                     SetRect(rct, 4, 4, 100, 100);
  455.                 end
  456.                 else
  457.                     BlockMove(ptr(longInt(hdl^) + GetHandleSize(hdl) - 10), @rct, SizeOf(rect));
  458.                 ger.int1 := left + right; { figure out why :-}
  459.                 ger.int2 := top + bottom;
  460.             end;
  461.         end; {proc}
  462.  
  463.         procedure FinishRuleBook;
  464.         begin
  465.             ger.globals := nil;
  466.         end;
  467.  
  468.         procedure CommonInit;
  469.             var
  470.                 k: integer;
  471.                 h: handle;
  472.                 rct: rect;
  473.         begin
  474.             GetDItem(gwindow, dialog_fillbar, k, h, rct);
  475.             SetDItem(gwindow, dialog_fillbar, k, handle(@DrawGame), rct);
  476.             SetWRefCon(gwindow, longInt(ghandle));
  477.             ggame^.globals := gglobals;
  478.             with ggame^ do begin
  479.                 send.state := F_None;
  480.                 receive.state := F_None;
  481.                 connectionstate := cs_Local;
  482.                 SetButtonState;
  483.             end;
  484.         end;
  485.  
  486.         procedure RestartGame;
  487.             var
  488.                 r: integer;
  489.         begin
  490.             SetMyTurn;
  491.             UpdateControls;
  492.         end;
  493.  
  494.         procedure NewGame;
  495.         begin
  496.             HUnlock(ghandle);
  497.             SetHandleSize(ghandle, SizeOf(gameRecord));
  498.             HLock(ghandle);
  499.             ggame := gamePeek(ghandle^);
  500.             CommonInit;
  501.             RestartGame;
  502.         end;
  503.  
  504.         procedure OldGame;
  505.         begin
  506.             CommonInit;
  507.             SetMyTurn;
  508.             UpdateControls;
  509.         end;
  510.  
  511.         procedure Swap;
  512.         begin
  513.             SetMyTurn;
  514.             UpdateControls;
  515.         end;
  516.  
  517.         procedure ConnectionLost;
  518.             procedure Finish (var fs: filespec);
  519.                 var
  520.                     oe: OSErr;
  521.             begin
  522.                 fs.state := F_None;
  523.                 if fs.refnum <> bad_refnum then
  524.                     oe := FSClose(fs.refnum);
  525.                 fs.refnum := bad_refnum;
  526.             end;
  527.         begin
  528.             with ggame^ do begin
  529.                 with ggame^ do begin
  530.                     Finish(send);
  531.                     Finish(receive);
  532.                     connectionstate := cs_Local;
  533.                     SetButtonState;
  534.                 end;
  535.                 SetMyTurn;
  536.             end; {with}
  537.         end;
  538.  
  539.         procedure ConnectionMade;
  540.         begin
  541.             with ggame^ do begin
  542.                 connectionstate := cs_Remote;
  543.                 SetButtonState;
  544.                 SetMyTurn;
  545.             end; {with}
  546.         end;
  547.  
  548.         procedure Restart;
  549.         begin
  550.             RestartGame;
  551.         end;
  552.  
  553.         procedure MouseDown;
  554.         begin
  555.             if (ger.int1 = dialog_button) and (ggame^.connectionState = cs_remote) then
  556.                 DoSend;
  557.         end;
  558.  
  559.         procedure MessageReceived;
  560.         begin
  561.             DoMove(ger.message);
  562.         end;
  563.  
  564.         procedure AnswerReceived;
  565.         begin
  566.             DoAnswer(ger.int1);
  567.         end;
  568.  
  569.     begin
  570.         gglobals := globalsPeek(ger.globals);
  571.         ghandle := ger.game;
  572.         if ghandle <> nil then begin
  573.             HLock(ghandle);
  574.             ggame := gamePeek(ghandle^);
  575.         end;
  576.         GetPort(gwindow);
  577.         case ger.event of
  578.             ge_InitRuleBook: 
  579.                 InitRuleBook;
  580.             ge_FinishRuleBook: 
  581.                 FinishRuleBook;
  582.             ge_NewGame: 
  583.                 NewGame;
  584.             ge_OldGame: 
  585.                 OldGame;
  586.             ge_ConnectionLost: 
  587.                 ConnectionLost;
  588.             ge_ConnectionMade: 
  589.                 ConnectionMade;
  590.             ge_MessageReceived: 
  591.                 MessageReceived;
  592.             ge_Answer: 
  593.                 AnswerReceived;
  594.             ge_MouseDown: 
  595.                 MouseDown;
  596.             ge_Swap: 
  597.                 Swap;
  598.             ge_Restart: 
  599.                 Restart;
  600.             ge_Idle: 
  601.                 DoIdle;
  602.             otherwise
  603.         end;
  604.         if ghandle <> nil then
  605.             HUnlock(ghandle);
  606.     end;
  607.  
  608. end.